package com.diy.sigmund.diyuser.test.controller;

import com.diy.sigmund.diycommon.entity.ResultMsg;
import com.diy.sigmund.diycommon.middleware.cache.redis.RedisService;
import com.diy.sigmund.diycommon.util.reflect.ReflectUtil;
import com.diy.sigmund.diycommon.util.time.LocalDateTimeUtil;
import com.diy.sigmund.diyuser.test.entity.RedisSetTestVO;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author ylm-sigmund
 * @since 2021/8/12 15:37
 */
@RestController
@RequestMapping("/redisSet")
public class RedisSetController {

    private static final Logger log = LoggerFactory.getLogger(RedisService.class);

    @Autowired
    private RedisService redisService;

    @PostMapping("/testSetCommand")
    public ResultMsg testSetCommand() {
        boolean set = redisService.set("a", "b", -3, TimeUnit.MILLISECONDS);
        System.out.println(set);
        return ResultMsg.success();
    }

    /**
     * 1、先将数组数据存储到缓存，（Set数据结构）
     * 2、redis中求交集
     * 3、求差集
     * 4、对差集处理
     * 5、输出结果
     */
    @PostMapping("/reconciliation")
    public ResultMsg reconciliation() {
        // 1、原始数据集合
        List<RedisSetTestVO> localInfo = getLocalInfo();
        List<RedisSetTestVO> outerInfo = getOuterInfo();
        // 2、待处理的字符串数据集合
        List<String> localList = getCompareFieldList(localInfo);
        List<String> outerList = getCompareFieldList(outerInfo);

        String nowDateTime = LocalDateTimeUtil.getLocalDateTimeStr();
        String localSetKey = getKey("{account}:localSet", nowDateTime);
        String outerSetKey = getKey("{account}:outerSet", nowDateTime);
        String interSetKey = getKey("{account}:interSet", nowDateTime);
        ///3、存储数据
        if (CollectionUtils.isNotEmpty(localList)) {
            redisService.sAddAndExpire(localSetKey, 30, TimeUnit.SECONDS,
                    // 将ArrayList集合转换成数组 https://blog.csdn.net/qq_31615049/article/details/89380369
                    localList.toArray(new String[localList.size()]));
        }
        if (CollectionUtils.isNotEmpty(outerList)) {
            redisService.sAddAndExpire(outerSetKey, 30, TimeUnit.SECONDS,
                    outerList.toArray(new String[outerList.size()]));
        }
        // 4、求交集
        redisService.sInterStore(localSetKey, outerSetKey, interSetKey, 30, TimeUnit.SECONDS);
        // 5、求差集
        String localDiffKey = getKey("{account}:localDiff", nowDateTime);
        String outerDiffKey = getKey("{account}:outerDiff", nowDateTime);
        redisService.sDiffStore(localSetKey, interSetKey, localDiffKey, 30, TimeUnit.SECONDS);
        redisService.sDiffStore(outerSetKey, interSetKey, outerDiffKey, 30, TimeUnit.SECONDS);
        // 获得交集数据
        final Set<Object> members = redisService.members(interSetKey);
        // 获得差集数据
        final Set<Object> localDiffSet = redisService.members(localDiffKey);
        final Set<Object> outerDiffSet = redisService.members(outerDiffKey);
        Set<Object> diffSet = new HashSet<>();
        diffSet.addAll(localDiffSet);
        diffSet.addAll(outerDiffSet);
        List<String> idList = getIdList(diffSet);
        // 6、比较差集不一致的字段
        final Map<String, RedisSetTestVO> localMap = localInfo.stream()
                .collect(Collectors.toMap(RedisSetTestVO::getId, redisSetTestVO -> redisSetTestVO,
                        (existing, replacement) -> existing));
        final Map<String, RedisSetTestVO> outerMap = outerInfo.stream()
                .collect(Collectors.toMap(RedisSetTestVO::getId, redisSetTestVO -> redisSetTestVO,
                        (existing, replacement) -> existing));
        List<RedisSetTestVO> result = new ArrayList<>();
        idList.forEach(
                id -> {
                    RedisSetTestVO localVo = localMap.get(id);
                    RedisSetTestVO outerVo = outerMap.get(id);
                    if (Objects.isNull(localVo)) {
                        localVo = new RedisSetTestVO();
                        localVo.setId(id);
                    }
                    if (Objects.isNull(outerVo)) {
                        outerVo = new RedisSetTestVO();
                        outerVo.setId(id);
                    }
                    final String diffField = ReflectUtil.compareFields(localVo, outerVo, getCompareList());
                    localVo.setDiffField(diffField);
                    outerVo.setDiffField(diffField);

                    result.add(localVo);
                    result.add(outerVo);
                }
        );

        // 返回差集数据
        return ResultMsg.success(result);
    }

    private List<String> getCompareList() {
        return Stream.of("id", "name", "desc").collect(Collectors.toList());
    }

    private List<String> getIdList(Set<Object> info) {
        List<String> ids = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(info)) {
            ids = info.stream().map(
                            o -> Optional.ofNullable(o).orElse("").toString().split(",")[0])
                    .filter(StringUtils::isNotEmpty)
                    .distinct()
                    .sorted(Comparator.naturalOrder())
                    .collect(Collectors.toList());
        }
        return ids;
    }

    private String getKey(String s, String nowDateTime) {
        return s + nowDateTime;
    }

    private List<String> getCompareFieldList(List<RedisSetTestVO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().map(obj -> obj.getId() + ","
                        + obj.getName() + ","
                        + obj.getDesc())
                .collect(Collectors.toList());
    }

    private List<RedisSetTestVO> getOuterInfo() {
        List<RedisSetTestVO> outerInfo = new ArrayList<>();
        outerInfo.add(new RedisSetTestVO("10", "治哥", "电脑"));
        outerInfo.add(new RedisSetTestVO("11111", "b哥", "鼠标"));
        outerInfo.add(new RedisSetTestVO("12", "洋芋芋芋芋", "键盘"));
        outerInfo.add(new RedisSetTestVO("13", "小明", "鼠标垫111"));
        return outerInfo;
    }

    private List<RedisSetTestVO> getLocalInfo() {
        List<RedisSetTestVO> localInfo = new ArrayList<>();
        localInfo.add(new RedisSetTestVO("10", "治哥", "电脑"));
        localInfo.add(new RedisSetTestVO("11", "b哥", "鼠标"));
        localInfo.add(new RedisSetTestVO("12", "洋芋", "键盘"));
        localInfo.add(new RedisSetTestVO("13", "小明", "鼠标垫"));
        return localInfo;
    }
}
